import os

import cv2
import numpy as np
import pandas as pd
from cnocr import CnOcr

# 排序的方法
LEFT_TO_RIGHT = 0
RIGHT_TO_LEFT = 1
BOTTOM_TO_TOP = 2
TOP_TO_BOTTOM = 3

# 数据集中各种图片的计数
selected = 0
unselected = 0
corner = 0
exam_num = 0
choices_question = 0

# 标签和其对应的索引
label_dict = {"choices_question": 0, "corner": 1, "exam_num": 2, "selected": 3, "unselected": 4}
label_list = ["choices_question", "corner", "exam_num", "selected", "unselected"]

# 选中的项的宽和高
selected_box_w = 50
selected_box_h = 28


def show_image(image, name="res"):
    """
    展示图片
    :param image: 图片
    :param name: 图片名字，默认“res”
    :return: 无
    """
    # print("hello")
    # cv2.namedWindow(name, cv2.WINDOW_NORMAL)
    cv2.imshow(name, image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


def sort_contours(contours, method=LEFT_TO_RIGHT):
    """
    轮廓排序
    :param contours: 需要排列的轮廓
    :param method: 排列的方法， 默认是LEFT_TO_RIGHT
    :return contours: 排列好的轮廓, boundingBoxes: 包裹轮廓的外接矩形
    """

    if contours is None or len(contours) == 0:
        return [], []

    # 初始化逆序标志和排序索引
    reverse = False
    i = 0

    # 是否需逆序处理
    if method == RIGHT_TO_LEFT or method == BOTTOM_TO_TOP:
        reverse = True

    # 是否需要按照y坐标函数
    if method == TOP_TO_BOTTOM or method == BOTTOM_TO_TOP:
        i = 1

    # 构造包围框列表，并从上到下对它们进行排序
    boundingBoxes = [cv2.boundingRect(c) for c in contours]
    (contours, boundingBoxes) = zip(*sorted(
        zip(contours, boundingBoxes), key=lambda b: b[1][i], reverse=reverse))

    # 返回已排序的轮廓线和边框列表
    return contours, boundingBoxes


def sort_boxes(boxes, method=LEFT_TO_RIGHT):
    """
    对矩形进行排序
    :param boxes: 需要排列的矩形
    :param method: 排序的方法，默认：LEFT_TO_RIGHT
    :return boxes: 排列好的矩形
    """
    if boxes is None or len(boxes) == 0:
        return [], []

    # 初始化逆序标志和排序索引
    reverse = False
    i = 0

    # 是否需逆序处理
    if method == RIGHT_TO_LEFT or method == BOTTOM_TO_TOP:
        reverse = True

    # 是否需要按照y坐标函数
    if method == TOP_TO_BOTTOM or method == BOTTOM_TO_TOP:
        i = 1

    boxes = sorted(boxes, key=lambda b: b[i], reverse=reverse)
    return boxes


def get_center_of_box(box):
    """
    获取矩形的中心点
    :param box: 矩形
    :return: centerX, centerY 中心点
    """
    (x, y, w, h) = box
    centerX = (2 * x + w) / 2
    centerY = (2 * y + h) / 2
    return centerX, centerY


def cover_area_of_two_boxes(a, b):
    x1, y1, w1, h1 = a
    x3, y3, w3, h3 = b
    x2 = x1 + w1
    y2 = y1 + h1
    x4 = x3 + w3
    y4 = y3 + h3
    if (x2 <= x3 or x4 <= x1) and (y2 <= y3 or y4 <= y1):
        return 0
    else:
        lens = min(x2, x4) - max(x1, x3)
        wide = min(y2, y4) - max(y1, y3)
        return lens * wide


def get_less_cover_boxes(boxes):
    result = []
    for box in boxes:
        flag = True
        area1 = box[2] * box[3]
        for r in result:
            area2 = r[2] * r[3]
            cover = cover_area_of_two_boxes(box, r)
            if cover > min(area1, area2) / 3.5:
                flag = False
                break
        if flag:
            result.append(box)
    return result


def is_point_in_box(x: float, y: float, box: tuple):
    """
    判断点(x, y)是否在矩形box中
    :param x:
    :param y:
    :param box:
    :return : bool值
    """
    minx, miny, w, h = box
    return minx < x < minx + w and miny < y < miny + h


def order_points(corners):
    """
    四边形四点排序
    :param corners: 需要排序的四个点
    :return: rect 返回4个顶点的顺序
    """
    rect = np.zeros((4, 2), dtype="float32")  # 按照左上、右上、右下、左下顺序初始化坐标

    s = np.sum(corners, axis=1)  # 计算点xy的和
    rect[0] = corners[np.argmin(s)]  # 左上角的点的和最小
    rect[2] = corners[np.argmax(s)]  # 右下角的点的和最大

    diff = np.diff(corners, axis=1)  # 计算点xy之间的差
    rect[1] = corners[np.argmin(diff)]  # 右上角的差最小
    rect[3] = corners[np.argmax(diff)]  # 左下角的差最小
    return rect  # 返回4个顶点的顺序


def get_image_by_contour(image, contour):
    """
    根据轮廓截取图片
    :param contour: 轮廓
    :param image: 原图
    :return result_image: 裁剪好的图片
    """
    peri = cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, 0.06 * peri, True)
    x, y, w, h = cv2.boundingRect(approx)
    result_image = image[y: y + h, x:x + w]
    return result_image


def get_image_by_box(image, box):
    """
    通过矩形裁剪图片
    :param image:原图
    :param box: 矩形
    :return result_image: 裁剪好的图片
    """
    x, y, w, h = box
    result_image = image[y: y + h, x:x + w]
    return result_image


def get_ocr_text_by_ocr(image, ocr: CnOcr):
    """
    使用CnOcr识别文字
    :param ocr: CnOcr对象
    :param image: 原图
    :return text: 识别的文字
    """
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    image = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    image = cv2.GaussianBlur(image, (3, 3), 0)
    # show_image(image)
    text = ocr.ocr_for_single_line(image)
    return text


def read_cnt():
    """
    读取数据集中每种图片的个数
    :return:
    """
    if os.path.exists('../dataset/cnt.csv'):
        read_df = pd.read_csv('../dataset/cnt.csv')
        global selected, unselected, corner, exam_num, choices_question
        selected = read_df['selected'][0]
        unselected = read_df['unselected'][0]
        corner = read_df['corner'][0]
        exam_num = read_df['exam_num'][0]
        choices_question = read_df['choices_question'][0]


def save_cnt():
    """
    保存数据集中每种图片的数量
    :return:
    """
    col = ['selected', 'unselected', 'corner', 'exam_num', 'choices_question']
    data = [[selected, unselected, corner, exam_num, choices_question]]
    df = pd.DataFrame(data, columns=col)
    df.to_csv('../dataset/cnt.csv', encoding='utf-8')


def cut_choices(path):
    """
    裁剪模板
    :param path: 模板路径
    :return:
    """
    image = cv2.imread(path)
    # result_image = cv2.morphologyEx(image, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))
    result_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    _, result_image = cv2.threshold(result_image, -1, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
    result_image = cv2.GaussianBlur(result_image, (5, 5), 0)
    contours, _ = cv2.findContours(result_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    all_contours = np.vstack(contours)
    # sorted(contours, key=cv2.contourArea, reverse=True)
    (x, y, w, h) = cv2.boundingRect(all_contours)
    # res = cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
    # show_image(res)
    temp_image = get_image_by_box(image, (x, y, w, h))
    cv2.imwrite(path, temp_image)


def generate_csv(path):
    """
    创建数据集的csv
    :param path: 数据集的路径
    :return:
    """
    dataset_dir = path
    classes = os.listdir(dataset_dir)

    info_array = []
    col = ['filename', 'filepath', 'label']
    for kindname in classes:
        classpath = dataset_dir + '/' + kindname
        if os.path.isdir(classpath):
            for filename in os.listdir(classpath):
                filepath = classpath + '/' + filename
                label = label_dict[kindname]
                info_array.append([filename, filepath, label])
    info_array = np.array(info_array)
    df = pd.DataFrame(info_array, columns=col)
    df.to_csv(path + "/dataset.csv", encoding='utf-8')


def data_enhancement(path: str, cnt):
    """
    通过灰度处理，高斯滤波对数据进行增强
    :param path: 需要增强的数据集的路径
    :param cnt: 对应数据在数据集中的计数
    :return:
    """
    names = os.listdir(path)
    for name in names:
        image_path = path + '/' + name
        image = cv2.imread(image_path)
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        cv2.imwrite(path + '/{}.jpg'.format(cnt), gray)
        cnt += 1
        blur = cv2.GaussianBlur(image, (5, 5), 1)
        cv2.imwrite(path + '/{}.jpg'.format(cnt), blur)
        cnt += 1
    return cnt


def get_selected_box_size(path="../choices/selected/selected.jpg"):
    """
    获取被选中模板图片的宽度和高度
    :param path:
    :return:
    """
    image = cv2.imread(path)
    global selected_box_w, selected_box_h
    selected_box_w = int(image.shape[1] * 0.8)
    selected_box_h = image.shape[0]


if __name__ == "__main__":
    # get_selected_box_size()
    pass
    # image = cv2.imread("../dataset/corner/1.jpg")
    # index, _ = My_vgg.judge_by_model(image, None, (224, 224))
    # print(index, label_list[index])
    # print(index, label)
    # generate_csv("../dataset")
    # read_cnt()
    # exam_num = data_enhancement("../dataset/exam_num", exam_num)
    # save_cnt()
